package com.iacrqq.sedaf.demo.sHttpServer.event.handler;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.iacrqq.sedaf.config.Configuration;
import com.iacrqq.sedaf.demo.sHttpServer.event.HttpEvent;
import com.iacrqq.sedaf.demo.sHttpServer.event.HttpEventStateEnum;
import com.iacrqq.sedaf.event.Event;
import com.iacrqq.sedaf.event.EventDispatcher;
import com.iacrqq.sedaf.event.EventHandler;
import com.iacrqq.sedaf.event.exception.EventHandlerException;

public class ListenerEventHandler implements EventHandler
{
	private static final Log logger = LogFactory.getLog(ListenerEventHandler.class);
	
	private String hostName; 							// 
	private int port;									//
	private ServerSocketChannel serverSocketChannel; 	//
	private Selector selector; 							//
	
	@Override
	public void init(Configuration config) throws Exception
	{
		port = config.getInt("listener.port");
		hostName = config.getString("listener.hostName");
		//port = 8206;
		//hostName = "iac-rqq.iac-rqq.com";
		
		selector = Selector.open();
		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.socket().bind(hostName == null ? new InetSocketAddress(port) : new InetSocketAddress(hostName, port));
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		
		logger.info(new StringBuilder("ListenerEventHandler listening on ").append(hostName).append(":").append(port).toString());
	}

	@Override
	public void destroy() throws Exception
	{
		if(selector != null)
		{
			selector.close();
		}
		
		if(serverSocketChannel != null)
		{
			serverSocketChannel.close();
		}
		
		System.out.println("ListenerEventHandler destroied.");
	}

	@Override
	public Event handleEvent(Event event, EventDispatcher eventDispatcher) throws EventHandlerException
	{
		try
		{
			SocketChannel channel = _accept_();
			
			if(channel != null)
			{
				Event initilizedEvent = new HttpEvent(0, channel);
				initilizedEvent.setState(HttpEventStateEnum.HTTP_EVENT_STATE_ACCEPTED.value());
				return initilizedEvent;
			}
		}
		catch(InterruptedException e)
		{
			logger.error(e);
			Thread.currentThread().interrupt();
		}
		
		return null;
	}

	@Override
	public Event[] handleEvents(Event[] events, EventDispatcher eventDispatcher) throws EventHandlerException
	{
		//System.out.println(new StringBuilder("ListenerEventHandler handle ").append(events.length).append(" events:").append(events).toString());
		
		return events;
	}
	
	// TODO
	private SocketChannel _accept_() throws InterruptedException
	{
		try
		{
			if (selector.select(1000) <= 0)
			{
				Thread.sleep(1000);
				return null;
			}
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

		while (iterator.hasNext())
		{
			SelectionKey key = (SelectionKey) iterator.next();
			iterator.remove();
			try
			{
				if (!key.isValid())
				{
					key.cancel();
					continue;
				}

				if (key.isAcceptable())
				{
					return _on_accept_(key);
				}
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		
		return null;
	}
	
	private SocketChannel _on_accept_(SelectionKey key) throws IOException
	{
		SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
		
		if (logger.isWarnEnabled())
		{
			logger.warn("Accept client from : " + channel.socket().getRemoteSocketAddress());
		}
		
		return channel;
	}
}
